#include "laurin-controller.h"
#include "../core/network/laurin-80211-network.h"
#include <sched.h>


/*************** LAURIN CONTROLLER OPTIONS ***************************************/


LaurinControllerOptions LaurinControllerOptions::getDefault()
{
	LaurinControllerOptions options;

	options.MasterDeviceName = "wmaster0";
	options.MonitorDeviceName = "mon0";
	options.NetworkDeviceName = "wlan0";
	options.NetworkTimeout = 2;
	options.MonitorMaxCapturedFrame = 1000;
	options.MonitorCaptureInterval = 10;
	options.EnableLocation = true;
	options.PassiveMode = true;


	return options;
}


bool LaurinControllerOptions::areValid()
{

	if(MasterDeviceName.empty() || MonitorDeviceName.empty())
	{
		_errmess = "Options not valid: Not all devices name are provided";
		return false;
	}


	if(MonitorCaptureInterval < 2 || MonitorMaxCapturedFrame < 10 || NetworkTimeout < 0)
	{
		_errmess = "Options not valid: Network parameters are not valid";
		return false;
	}

	if(!PassiveMode && (NetworkDeviceName.empty() || NetworkTimeout < 0 ))
	{
		_errmess = "Options not valid: Passive mode isn't selected and network parameters are not valid.";
		return false;
	}


	return true;
}


Glib::ustring LaurinControllerOptions::getErrorMessage() const
{
	return _errmess;
}



/*********************************************************************************/







LaurinController::LaurinController() : LaurinModuleHandler()
{
	_options = LaurinControllerOptions::getDefault();
	_modules_created = false;

	_devices_scan_module = NULL;
	_network_client_scan_module = NULL;
}


LaurinController::~LaurinController()
{
	clearResources();
}


bool LaurinController::setOptions(LaurinControllerOptions options)
{
	if(isRunning())
	{
		setError("Modules are running. Can't change while they are running.");
		return false;
	}

	if(!options.areValid())
	{
		setError(options.getErrorMessage());
		return false;
	}


	invalidateModules(options);
	_options = options;
	return true;
}


LaurinControllerOptions LaurinController::getOptions() const
{
	return _options;
}


LaurinScanResultModel* LaurinController::getScanResultModel()
{
	if(isRunning())
	{
		setError("Modules are running. Can't get result while they are running.");
		return NULL;
	}

	return fillResult();
}


bool LaurinController::start()
{
	if(isRunning())
	{
		setError("Modules are alredy running. Can't start twice.");
		return false;
	}

	if(!createModules())
		return false;

	startHandler((_options.PassiveMode) ? 1 : 2);

	_devices_scan_module->start();

	if(!_options.PassiveMode)
	{
		sched_yield();
		_network_client_scan_module->start();
	}

	return true;
}


bool LaurinController::stop(bool wait)
{
	if(!isRunning())
	{
		setError("Modules are not running");
		return false;
	}

	if(!_options.PassiveMode)
		_network_client_scan_module->stop(wait);

	_devices_scan_module->stop(wait);

	return true;
}


LaurinScanResultModel* LaurinController::fillResult()
{

	LaurinScanResultModel* result = new LaurinScanResultModel();

	result->set80211NetworkSet(_devices_scan_module->getNetworkSet());
	result->setIPNetwork((_options.PassiveMode) ? NULL : _network_client_scan_module->getIPNetwork());
	result->fillResult();

	return result;
}


bool LaurinController::setDistanceBetweenMonitorAndAP(Glib::ustring bssid, double distance)
{
	if(isRunning())
	{
		setError("Modules are working. Can't set distance while they working.");
		return false;
	}


	Laurin80211Network* network = _devices_scan_module->getNetworkSet()->isNetworkPresent(bssid);
	network->setDistanceBetweenMonitorAndAP(bssid, distance);


	return true;
}


void LaurinController::invalidateModules(LaurinControllerOptions options)
{
	if(options.MonitorDeviceName != _options.MonitorDeviceName ||
			options.MasterDeviceName != _options.MasterDeviceName   ||
			(options.PassiveMode != _options.PassiveMode || options.NetworkDeviceName != _options.NetworkDeviceName ))
	{
		clearResources();
	}
}


void LaurinController::clearResources()
{
	if(isRunning())
	{
		_devices_scan_module->stop(true);

		if(!_options.PassiveMode)
			_network_client_scan_module->stop(true);
	}

	if(_modules_created)
	{
		delete _devices_scan_module;

		if(!_options.PassiveMode)
			delete _network_client_scan_module;

		_modules_created = false;
	}
}


bool LaurinController::createModules()
{

	if(!_modules_created)
	{
		_devices_scan_module = new LaurinDiscoverDevicesModule(_options.MonitorDeviceName, _options.MasterDeviceName, this);
		_devices_scan_module->setCaptureInterval(_options.MonitorCaptureInterval);
		_devices_scan_module->setMaxNumberOfCapturedFrame(_options.MonitorMaxCapturedFrame);
		_devices_scan_module->setLocationEnable(_options.EnableLocation);



		if(!_devices_scan_module->isInitialized())
		{
			setError(_devices_scan_module->getErrorMessage());

			delete _devices_scan_module;
			_devices_scan_module = NULL;

			return false;
		}


		if(!_options.PassiveMode)
		{
			_network_client_scan_module = new LaurinDiscoverNetworkClientsModule(_options.NetworkDeviceName, this);
			_network_client_scan_module->setPacketTimeout(_options.NetworkTimeout);


			if(!_network_client_scan_module->isInitialized())
			{
				setError(_network_client_scan_module->getErrorMessage());

				delete _network_client_scan_module;
				delete _devices_scan_module;


				_devices_scan_module = NULL;
				_network_client_scan_module = NULL;

				return false;
			}
		}

		_modules_created = true;
	}

	return true;
}


